﻿using BlockMain_Class;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Threading;
using System.Linq;
using System.Collections.Generic;

namespace BlockMain_Peer
{
    class Program
    {

        public static string nowpeer = "";
        static string account = "";
        static string pwd = "";
        public static MongodbHelpers<PeerList> mon = new MongodbHelpers<PeerList>();
        public static ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("127.0.0.1:6379");
        //当前节点是否是领袖节点 固定领袖 不走选举
        public static bool issuper = false;
        //验证监听是否已部署过
        public static bool isToFollower = false;
        public static bool isCopy = false;
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("----------------------------警告：退出控制台,服务将暂停监听----------------------------");
                Console.WriteLine("请在下方输入数字： 1-登录  2-注册");
                var num = Console.ReadLine();
                if (num == "1")
                {
                    login();
                }
                else
                {
                    register();
                }


            }
            catch (Exception e)
            {

                Console.WriteLine("出错信息:" + e.Message);
                Console.ReadKey();
            }
        }

        /// <summary>
        /// 注册账号
        /// </summary>
        public static void register()
        {
            Console.WriteLine("请输入节点账号:");
            var account = Console.ReadLine();
            Console.WriteLine("请输入节点密码:");
            var pwd = Console.ReadLine();
            //验重
            var ischeck = mon.QueryByFirst(a => a.Account == account);
            if (ischeck != null)
            {
                Console.WriteLine("已存在,重新输入");
                register();
            }
            PeerList p = new PeerList();
            p.Account = account;
            p.Password = pwd;
            p.PeerIp = "127.0.0.1";
            p.Port = 4000;
            p.Detail = "检测节点，具有完善的检测经验及有效的证书颁发机构";
            var now = mon.Insert(p);
            //注册成功 修改缓存
            GetPeerList.Update();
            //复制已存在链表
            var val = GetALl();
            PeerDB.dbName = "Peer_" + now.Id.ToString(); //当前节点
            PeerMongodbHelpers<AccountBook> mons = new PeerMongodbHelpers<AccountBook>();//节点账本DB
            mons.InsertBatch(val);
            Console.WriteLine("注册成功,按1登录");
            var num = Console.ReadLine();
            if (num == "1")
            {
                login();
            }
            Console.ReadKey();
        }


        public static List<AccountBook> GetALl()
        {
            //领袖节点
            var nowpeer = mon.QueryAll().First().Id.ToString();
            PeerDB.dbName = "Peer_" + nowpeer; //当前节点
            PeerMongodbHelpers<AccountBook> mons = new PeerMongodbHelpers<AccountBook>();//节点账本DB
            return mons.QueryAll();
        }

        /// <summary>
        /// 登录开始监听服务
        /// </summary>
        public static void login()
        {
            Console.WriteLine("请输入节点账号:");
            account = Console.ReadLine();
            Console.WriteLine("请输入节点密码:");
            pwd = Console.ReadLine();
            //获取节点
            var list = mon.QueryAll();
            var first = list.FirstOrDefault(a => a.Account == account && a.Password == pwd);
            if (first != null)
            {
                nowpeer = first.Id.ToString();
                //分配领袖节点
                if (first.Id == list.First().Id)
                {
                    issuper = true;
                }

                if (issuper)
                {

                    //是领袖操作
                    ISubscriber sub = redis.GetSubscriber();
                    //1)处理peer队列
                    sub.Subscribe("peer", (channel, message) =>
                    {
                        //输出收到的消息
                        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {message}");
                        var data = message;
                        ToFollower(data);
                    });
                }
                else
                {
                    //群众操作
                    ISubscriber sub = redis.GetSubscriber();
                    //1)处理conn队列
                    sub.Subscribe("conn", (channel, message) =>
                    {
                        //输出收到的消息
                        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {message}");
                        var data = message;
                        PubState(data);
                    });

                }

                //1)处理copy队列

                ISubscriber sub2 = redis.GetSubscriber();
                sub2.Subscribe("copy", (channel, message) =>
                {
                    //输出收到的消息
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {message}");
                    var data = message;
                    AddBlockItem(data);
                });

                Console.WriteLine("已在监听...");
                Console.ReadKey();
            }
            else
            {
                Console.WriteLine("密码输入错误,重新输入.");
                login();
            }
        }

        /// <summary>
        /// 处理peer队列  填入conn队列 广播给群众节点 【领袖节点执行】
        /// </summary>
        /// <param name="data"></param>
        public static void ToFollower(object data)
        {
            try
            {
                //添加队列conn
                //发布订阅
                Cache.Sub("conn", data.ToString());
                //单独开启线程监听
                ISubscriber sub = redis.GetSubscriber();
                if (!isToFollower)
                {
                    //订阅succ队列 验证返回结果集是否大于一半
                    sub.Subscribe("succ", (channel, message) =>
                    {
                        //输出收到的消息
                        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {message}");
                        CheckSuccess(message);
                    });
                    isToFollower = true;
                }

                Console.WriteLine("已处理peer队列..");
            }
            catch (Exception e)
            {
                Console.WriteLine("ToFollower出错信息" + e.Message);
            }
        }

        private static Object thisLock = new Object();

        /// <summary>
        /// 验证成功队列【领袖节点执行】
        /// </summary>
        /// <param name="data"></param>
        public static void CheckSuccess(object data)
        {
            try
            {
                //无作用的锁？
                lock (thisLock)
                {
                    //获取缓存数据
                    var peerlist = GetPeerList.Get();
                    //总节点数
                    var pnum = peerlist.Count();
                    //验证目前通过节点数
                    var num = 0;

                    foreach (var item in peerlist)
                    {
                        if (item == nowpeer)
                        {
                            continue;
                        }
                        JsonData val = Cache.Get<JsonData>(item + data);
                        if (val != null)
                        {
                            if (val.values == "ok")
                            {
                                num++;
                            }
                        }
                    }
                    //todo:暂时设定全部通过为准
                    if (num == (pnum - 1))
                    { //(num > (pnum / 2)) {
                      //超过半数 通知客户端
                      //删除缓存的结果 以防止重复验证【排他锁】
                        foreach (var item in peerlist)
                        {
                            Cache.Remove(item + data);
                        }
                        //放入copy队列
                        Cache.Sub("copy", data.ToString());

                    }
                    Console.WriteLine("已处理succ队列..");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("CheckSuccess已出错" + e.Message);
            }
        }



        /// <summary>
        /// 处理conn订阅，修改状态为1即可【群众节点执行】
        /// </summary>
        /// <param name="r"></param>
        public static void PubState(object data)
        {
            try
            {


                JsonData json = new JsonData();
                json.values = "ok";
                //写入缓存数据
                Cache.Insert<JsonData>(nowpeer + data, json, 3600);
                //发布succ推送
                Cache.Sub("succ", data.ToString());

                Console.WriteLine("已处理conn队列..");
                //var jsondata = Cache.Get(data.ToString());
                //List<Record> r = JsonConvert.DeserializeObject<List<Record>>(jsondata.ToString());
                ////合约逻辑处理【链上代码】【拓展层】
                ///****通用合约****/
                //var iss = PublicContract.Check(r);
                ///****通用合约****/
                //if (iss)
                //{
                //    //修改缓存
                //    r.State = 1;
                //    //处理消息入链【存储层】
                //    //AddBlock.Add(r, nowpeer);
                //    //更新数据
                //    Cache.Insert<Record>(data.ToString(), r, 3600);

                //    //发布succ推送
                //    Cache.Sub("succ", data.ToString());


                //    Console.WriteLine("已处理..");
                //}
            }
            catch (Exception e)
            {
                Console.WriteLine("PubState出错信息" + e.Message);
            }
        }

        /// <summary>
        /// 处理可以入链的数据【领袖节点执行】【群众节点执行】
        /// </summary>
        /// <param name="data"></param>
        public static void AddBlockItem(object data)
        {
            try
            {
                var jsondata = Cache.Get(data.ToString());
                Record r = JsonConvert.DeserializeObject<Record>(jsondata.ToString());
                AddBlock.Add(r, nowpeer);
                Console.WriteLine("已处理copy队列..");
            }
            catch (Exception e)
            {
                Console.WriteLine("AddBlockItem出错信息" + e.Message);
            }

        }

    }
}
